﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Timers;

namespace GoodStuff
{
    public static class StaticState
    {
        private class StateEntry
        {
            public object Data { get; set; }
            public DateTime Expires { get; set; }
        }

        private static IDictionary<Guid, StateEntry> storage = new Dictionary<Guid, StateEntry>();
        private static Timer collectorTimer;
        private static object __collectionLock = new object();

        public static T Retrieve<T>(Guid key)
        {
            lock (__collectionLock)
            {
                if (storage.ContainsKey(key))
                {
                    StateEntry entry = storage[key];
                    if (DateTime.Now <= entry.Expires)
                    {
                        return (T)entry.Data;
                    }
                }
                return default(T);
            }
        }

        public static Guid Store<T>(T item, TimeSpan expires)
        {
            Guid newKey = Guid.NewGuid();
            lock (__collectionLock)
            {
                storage.Add(newKey, new StateEntry() { Data = item, Expires = DateTime.Now + expires });
            }
            UpdateCollector();
            return newKey;
        }

        public static void Forget(Guid key)
        {
            lock (__collectionLock)
            {
                if (storage.ContainsKey(key))
                {
                    storage.Remove(key);
                }
            }
        }

        public static T GetAndForget<T>(Guid key)
        {
            lock (__collectionLock)
            {
                if (storage.ContainsKey(key))
                {
                    StateEntry entry = storage[key];
                    if (DateTime.Now <= entry.Expires)
                    {
                        T result = (T)entry.Data;
                        storage.Remove(key);
                        return result;
                    }
                }
                return default(T);
            }
        }

        public static void UpdateCollector()
        {
            if (collectorTimer == null)
            {
                collectorTimer = new Timer();
                collectorTimer.AutoReset = false;
                collectorTimer.Interval = TimeSpan.FromSeconds(2).TotalMilliseconds;
                collectorTimer.Elapsed += new ElapsedEventHandler(collectorTimer_Elapsed);
                collectorTimer.Start();
            }
        }

        static void collectorTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            lock (__collectionLock)
            {
                var itemsToKill = storage.Where(p => DateTime.Now > p.Value.Expires).ToList();
                foreach (var item in itemsToKill)
                {
                    storage.Remove(item.Key);
                    if (item.Value is IDisposable)
                    {
                        ((IDisposable)item.Value).Dispose();
                    }
                }

                if (storage.Count == 0)
                {
                    if (collectorTimer != null)
                    {
                        collectorTimer.Stop();
                        collectorTimer = null;
                    }
                }
                else
                {
                    collectorTimer.Start();
                }
            }
        }
    }
}
